// 版权所有2011 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package unicode

// U+0100下每个代码点的位掩码，用于快速查找。
const (
	pC     = 1 << iota // 一个控制字符。
	pP                 // 标点符号。
	pN                 // 一个数字。
	pS                 // 一个符号字符。
	pZ                 // 一个空格字符。
	pLu                // 大写字母。
	pLl                // 小写字母。
	pp                 // 根据Go的定义，可打印字符。
	pg     = pp | pZ   // 符合Unicode定义的图形字符。
	pLo    = pLl | pLu // 一个既不大写也不小写的字母。
	pLmask = pLo
)

// GraphicRanges根据Unicode定义图形字符集。
var GraphicRanges = []*RangeTable{
	L, M, N, P, S, Zs,
}

// PrintRanges根据Go定义可打印字符集。
// ASCII空间U+0020单独处理。
var PrintRanges = []*RangeTable{
	L, M, N, P, S,
}

// IsGraphic报告符文是否由Unicode定义为图形。
// 这些字符包括字母、标记、数字、标点符号、符号和
// 空格，来自L、M、N、P、S、Zs类。
func IsGraphic(r rune) bool {
	// 我们转换为uint32以避免额外的阴性测试，
	// 在索引中，我们转换为uint8以避免范围检查。
	if uint32(r) <= MaxLatin1 {
		return properties[uint8(r)]&pg != 0
	}
	return In(r, GraphicRanges...)
}

// iPrint报告符文是否定义为可由Go打印。此类
// 字符包括字母、标记、数字、标点符号、符号，以及
// ASCII空格字符，来自类别L、M、N、P、S和ASCII空格
// 字符。该分类与IsGraphic相同，只是
// 唯一的空格字符是ASCII空格U+0020。
func IsPrint(r rune) bool {
	if uint32(r) <= MaxLatin1 {
		return properties[uint8(r)]&pp != 0
	}
	return In(r, PrintRanges...)
}

// IsOneOf报告符文是否属于其中一个范围。
// 函数“In”提供了更好的签名，应该优先于IsOneOf使用。
func IsOneOf(ranges []*RangeTable, r rune) bool {
	for _, inside := range ranges {
		if Is(inside, r) {
			return true
		}
	}
	return false
}

// In报告符文是否属于其中一个范围。
func In(r rune, ranges ...*RangeTable) bool {
	for _, inside := range ranges {
		if Is(inside, r) {
			return true
		}
	}
	return false
}

// IsControl报告符文是否为控制字符。
// C（其他）Unicode类别包含更多代码点
// 例如代理；使用Is（C，r）来测试它们。
func IsControl(r rune) bool {
	if uint32(r) <= MaxLatin1 {
		return properties[uint8(r)]&pC != 0
	}
	// 所有控制字符都<MaxLatin1。
	return false
}

// IsLetter报告符文是否为字母（L类）。
func IsLetter(r rune) bool {
	if uint32(r) <= MaxLatin1 {
		return properties[uint8(r)]&(pLmask) != 0
	}
	return isExcludingLatin(Letter, r)
}

// IsMark报告符文是否为标记字符（M类）。
func IsMark(r rune) bool {
	// 拉丁语-1中没有标记字符。
	return isExcludingLatin(Mark, r)
}

// IsNumber报告符文是否为数字（类别N）。
func IsNumber(r rune) bool {
	if uint32(r) <= MaxLatin1 {
		return properties[uint8(r)]&pN != 0
	}
	return isExcludingLatin(Number, r)
}

// ispunt报告符文是否为Unicode标点字符
// （P类）。
func IsPunct(r rune) bool {
	if uint32(r) <= MaxLatin1 {
		return properties[uint8(r)]&pP != 0
	}
	return Is(Punct, r)
}

// IsSpace报告符文是否为Unicode的空白属性定义的空格字符；在拉丁-1空间中，这是
// 这是
// /'\t'，'\n'，'\v'，'\f'，'\r'，''，U+0085（NEL），U+00A0（NBSP）。
// 间距字符的其他定义按类别
// Z和属性模式_White_Space设置。
func IsSpace(r rune) bool {
	// 此属性与Z不同；特例。
	if uint32(r) <= MaxLatin1 {
		switch r {
		case '\t', '\n', '\v', '\f', '\r', ' ', 0x85, 0xA0:
			return true
		}
		return false
	}
	return isExcludingLatin(White_Space, r)
}

// IsSymbol报告符文是否为符号字符。
func IsSymbol(r rune) bool {
	if uint32(r) <= MaxLatin1 {
		return properties[uint8(r)]&pS != 0
	}
	return isExcludingLatin(Symbol, r)
}
